Point of Sale API Developer Guide

Introduction

This article describes the Loyalty APIs that allow third-party Point of Sale (POS) systems, such as MICROS RES, RICS, and Squirrel POS, to communicate with the Loyalty platform.

The intended audience for this article are developers responsible for integrating third-party POS systems with Loyalty. These developers require technical knowledge for invoking and debugging API calls using OAuth, REST, and JSON.

Use Cases

The Loyalty POS APIs supports the following use cases:

  • Assign a Member to a transaction

  • Unassign a Member from a transaction

  • Submit a transaction to Loyalty

  • Get Member summary / balance

  • Activate a physical card

  • Replace a physical card

The sequence diagram below describes a typical flow of API calls between the POS system and the Loyalty platform.

API Details

This section describes the API endpoints, with their corresponding parameter and response structures.

These endpoints can be accessed via either Loyalty’s Member API or Program API.

  • Program API base URL: /program/api/pos/stellar

  • Member API base URL: /api/pos/stellar

The owner of the access_token is set as the primary account in each API request.

Assign Member (“Get Offers Transaction”)

Clients can use this API to validate a Member, and to apply qualifying discounts earned from previous transactions. The POS system is responsible for applying the discounts to the open transaction.

This API utilizes Loyalty’s Discount Service to calculate the available discounts. The POS system submits the transaction line items, then this API validates the Member account and returns all possible rewards. The POS system should call this API every time the transaction details changes, such as after adding or removing of items, comps, or other discounts on the transaction.

Copy
PUT <base_url>?access_token=<access_token> 
{
    "status": String, 
    "timestamp": Timestamp, 
    "store_id": String, 
    "terminal_id": String, 
    "transaction_id": String, 
    "operator_id": String, 
    "accounts": [ 
        { 
            "identifier": String, 
            "identifier_type": String 
        } 
    ], 
    "items": [ 
        {
            "level": Integer, 
            "line_number": Integer, 
            "parent_line_number": Integer, 
            "name": String, 
            "description": String, 
            "sku": String, 
            "categories": Array, 
            "quantity": Decimal, 
            "unit_price": Decimal, 
            "discountable": Boolean 
        } 
    ], 
"    coupons": [ 
        { 
            "type": String, 
            "pos_code": String, 
            "stellar_code": String, 
            "name": String, 
            "quantity": Float, 
            "value": BigDecimal, 
            "items": [ 
                { 
                    "line_number": Integer 
                } 
            ] 
        } 
    ], 
    "summary": 
        { 
            "subtotal": Decimal, 
            "discount": Decimal, 
            "service_charge": Decimal, 
            "tax": Decimal, 
            "payment": Decimal 
        } 

Below is a sample request message.

Copy

    "status": "assign_member", 
    "timestamp": "2017-09-27T00:00:00Z", 
    "store_id": "1", 
    "terminal_id": "1", 
    "transaction_id": "1", 
    "operator_id": "1", 
    "accounts": [ 
        { 
            "identifier": "6011888052563949",
            "identifier_type": "card_id" 
        } 
    ], 
    "items": [ 
        { 
            "level": 0, 
            "line_number": 1, 
            "parent_line_number": 0, 
            "name": "Fries", 
            "description": "Cheese Fries", 
            "sku": "401301", 
            "categories": [ 
                "102"
            ], 
            "quantity": 1, 
            "unit_price": 5.25, 
            "discountable": true 
        } 
    ], 
    "coupons": [], 
    "summary": 
        { 
            "subtotal": 6.25, 
            "discount": 0, 
            "service_charge": 0, 
            "tax": 1, 
            "payment": 0 
        } 
    } 

Below is a sample response message to the above request.

Copy

    "messages": { 
        "display": [ 
            { 
                "message": "Adding guest - Michael Jordan.\\n\\nApplied the 
following rewards:\\nFree Fries" 
            } 
        ], 
        "receipt": [] 
    }, 
    "accounts": [ 
        { 
            "identifier": "michael@jordan.com", 
            "valid": true, 
            "name": "Michael Jordan", 
            "member_id": "S-000105990" 
        }
    ], 
    "add_coupons": [ 
        { 
            "type": "stellar", 
            "pos_code": "904", 
            "stellar_code": "OfferResponse-1", 
            "name": "Free Fries", 
            "quantity": 1, 
            "value": 5.25, 
            "items": [ 
                { 
                    "line_number": "1" 
                } 
            ] 
        ] 
    } 

Unassign Member

Clients can use this API to unassign a previously assigned Member from an open transaction. For example, after swiping a wrong card or entering an incorrect phone number on the POS system. This API instructs the Loyalty platform to remove the Member from the current transaction, and to make the Member’s discounts available for another transaction.

Copy
PUT <base_url>?access_token=<access_token> 
{
    "status": "unassign_member", 
    "timestamp": Timestamp, 
    "store_id": String, 
    "terminal_id": String, 
    "transaction_id": String, "operator_id": String, 
    "accounts": [ 
        { 
            "identifier": String, 
            "identifier_type": String 
        } 
    ] 

Below is a sample request message.

Copy

    "status": "unassign_member", 
    "timestamp": "2017-09-27T00:00:00Z", 
    "store_id": "1", 
    "terminal_id": "1", 
    "transaction_id": "1", 
    "operator_id": "1", "accounts": [ 
        { 
            "identifier": "6011888052563949", 
            "identifier_type": "card_id" 
        } 
    ] 
}

Below is a sample response message to the above request.

Copy

    "messages": 
        { 
            "display": [ 
                { 
                    "message": "Unassigned guest - Michael Jordan." 
                } 
            ], 
            "receipt": [] 
        }, 
    "accounts": [ 
        { 
            "identifier": "6011888052563949", 
            "valid": true, 
            "name": "Michael Jordan", 
            "member_id": "S-000105990" 
        } 
    ], 
    "remove_coupons": [ 
        { 
            "type": "stellar", "pos_code": "904", 
            "stellar_code": "OfferResponse-1", 
            "name": "Free Fries", 
            "quantity": 1, 
            "value": 5.25, 
            "items": [ 
                { 
                    "line_number": "1" 
                } 
            ] 
        }
    ] 

Finalize Transaction (“Submit Transaction”)

After all items are input into the transaction, clients can use this API to finalize and close the transaction with Loyalty. This API logs the transaction with the previously assigned Member, and performs all possible calculations for the Member to accrue Metrics, earn discounts, trigger emails, and so on. This API marks discounts that were used in the transaction as "Used." This API responds with messages that the POS could display or print on a receipt.

Shell Account

In the case when the Member does not exist in the Loyalty database based on their identifier, the platform will create a shell "visitor" account with the profile Attributes specified in the POST request. After creating the shell account, Loyalty assigns the transaction to this new account.

In the case where the profile Attributes are in conflict with an existing Member account, the shell account will be created without the Attributes, so that the card issued continues to work.

In the case when the primary identifier is in conflict (e.g., card ID, phone number, email), then the account will not be created. However, a conflict could occur in the secondary identifier. For example, let's say the account is identified by phone number in the identifier field, and email is passed in the profile section, and the email has an issue but the phone number is valid. In this scenario, Loyalty creates the new account but leaves the email not updated. In this same example, if the phone number already exists, then Loyalty will not create the new account.

Update Profile

This API will try to update profile Attributes for existing Members based on their identifier. In case the profile update fails, then the transaction will be assigned to the Member without updating their profile.

Copy
POST <base_url>?access_token=<access_token> 
{
    "status": String, 
    "timestamp": Timestamp, 
    "store_id": String, 
    "terminal_id": String, 
    "transaction_id": String, 
    "operator_id": String, 
    "accounts": [ 
        { 
            "identifier": String, 
            "identifier_type": String
            "profile": 
                { 
                    "member_attribute_name":"<value">, 
                    "member_attribute_name":"<value">, 
                    "member_attribute_name":"<value"> 
                } 
            } 
        ], 
        "items": [ 
            { 
                "level": Integer, 
                "line_number": Integer, 
                "parent_line_number": Integer, 
                "name": String, 
                "description": String, 
                "sku": String, 
                "categories": Array, 
                "quantity": Decimal, 
                "unit_price": Decimal, 
                "discountable": Boolean 
            } 
        ], 
        "coupons": [ 
            { 
                "type": String, 
                "pos_code": String, 
                "stellar_code": String, 
                "name": String, 
                "quantity": Float, 
                "value": BigDecimal, 
                "items": [ 
                    { 
                        "line_number": Integer 
                    } 
                ] 
            } 
        ], 
        "summary": 
            { 
                "subtotal": Decimal, 
                "discount": Decimal, 
                "service_charge": Decimal, 
                "tax": Decimal, 
                "payment": Decimal 
            } 
        } 

Below is a sample request message.

Copy

    "status": "submit_transaction", 
    "timestamp": "2017-09-27T00:00:00Z", 
    "store_id": "1", 
    "terminal_id": "1", 
    "transaction_id": "1", 
    "operator_id": "1", 
    "accounts": [ 
        { 
            "identifier": "6011888052563949", 
            "identifier_type": "card_id" 
        } 
    ], 
    "items": [ 
        { 
            "level": 0, 
            "line_number": 1, 
            "parent_line_number": 0, 
            "name": "Fries", 
            "description": "Cheese Fries", 
            "sku": "401301", 
            "categories": [ 
                "102" 
            ], 
            "quantity": 1,         
            "unit_price": 5.25, 
            "discountable": true 
        } 
    ], 
    "coupons": [ 
        { 
            "type": "stellar", "pos_code": "904", 
            "stellar_code": "OfferResponse-1", 
            "name": "Free Fries", 
            "quantity": 1, 
            "value": 5.25, "items": [ 
                { 
                    "line_number": "1" 
                } 
            ] 
        } 
    ], 
    "summary": 
        { 
            "subtotal": 1.00, 
            "discount": 5.25,
            "service_charge": 0.00, 
            "tax": 1.00, 
            "payment": 0.00 
        } 
    } 
 

Below is a sample response message to the above request.

Copy

    "messages": 
        { 
            "display": [ 
                { 
                    "message": "Thank you and come again soon!" 
                } 
            ], 
            "receipt": [] 
        },     
    "accounts": [ 
        { 
            "identifier": "michael@jordan.com", 
            "valid": true, 
            "name": "Michael Jordan", 
            "member_id": "S-000105990" 
        } 
    ] 

Get Member Summary

This API allows the cashier to look up a Member’s current balance and available discounts.

Copy
PUT <base_url>?access_token=<access_token> 

    "status": "member_summary", 
    "timestamp": Timestamp, 
    "store_id": String, 
    "terminal_id": String, 
    "transaction_id": String, 
    "operator_id": String, 
    "accounts": [ 
        { 
            "identifier": String, 
            "identifier_type": String
        } 
    ] 

Below is a sample request message.

Copy

    "status": "member_summary", 
    "timestamp": "2017-09-27T00:00:00Z", 
    "store_id": "1", 
    "terminal_id": "1", 
    "transaction_id": "1", 
    "operator_id": "1", 
    "accounts": [ 
        { 
            "identifier": "370615108474724", 
            "identifier_type": "card_id" 
        } 
    ] 

Below is a sample response message to the above request.

Copy

    "messages": 
        { 
            "display": [ 
                { 
                    "message":"Name: Michael Jordan\\nMember ID: 
S-000105990\\nBalance: 100 points\\n\\nRewards:\\n(2) Free Fries\\nFree 
Pizza\\n(2) $5-Gift Cards with $10.00-value" 
                } 
            ], 
            "receipt": [] 
        }, 
    "accounts": [ 
        { 
            "identifier": "370615108474724", 
            "valid": true, 
            "name": "Michael Jordan", 
            "member_id": "S-000105990" 
        } 
    ] 

Activate Card

This API allows the cashier to activate a new loyalty card. In this process, Loyalty creates a shell "visitor" account that is eligible to earn Metrics and other rewards on every transaction. After this process, the customer is expected to register online and update this shell account to complete their registration process. Only from that point will the customer will be able to use and redeem any of their previously earned Metrics and rewards.

Card activation can be done in two ways: with or without any pending transaction.

API Without Transaction

This API supports the scenario where the customer only wants to activate their card without making a purchase.

Copy
PUT <base_url>?access_token=<access_token> 

    "status": "activate_card", 
    "timestamp": Timestamp, 
    "store_id": String, 
    "terminal_id": String, 
    "transaction_id": String, 
    "operator_id": String, 
     "accounts": [ 
        { 
            "identifier": String, 
            "identifier_type": String 
        } 
    ] 

Below is a sample request message.

Copy

    "status": "activate_card", 
    "timestamp": "2017-09-27T00:00:00Z", 
    "store_id": "1", 
    "terminal_id": "1", 
    "transaction_id": "1", 
    "operator_id": "1", 
    "accounts": [ 
        { 
            "identifier": "370615108474724", 
            "identifier_type": "card_id" 
        } 
    ] 
}

Below is a sample response message to the above request.

Copy

    "messages": 
        { 
            "display": [ 
                { 
                    "message": "Card #370615108474724 activated." 
                } 
            ], 
            "receipt": [] 
        }, 
    "accounts": [ 
        { 
            "identifier": "370615108474724", 
            "valid": true 
        } 
    ] 

API With a Transaction

Clients can this API to link a pending transaction to the shell account that Loyalty will create upon closing the transaction.

Copy
PUT <base_url>?access_token=<access_token> 

    "status": String, 
    "timestamp": Timestamp, 
    "store_id": String, 
    "terminal_id": String, 
    "transaction_id": String, 
    "operator_id": String, 
    "accounts": [ 
        { 
            "identifier": String, 
            "identifier_type": String 
        } 
    ], 
    "items": [ 
        { 
            "level": Integer, 
            "line_number": Integer, 
            "parent_line_number": Integer, 
            "name": String, 
            "description": String, 
            "sku": String,
            "categories": Array, 
            "quantity": Decimal, 
            "unit_price": Decimal, 
            "discountable": Boolean 
        } 
    ], 
    "coupons": Array, 
    "summary": 
        { 
            "subtotal": Decimal, 
            "discount": Decimal, 
            "service_charge": Decimal, 
            "tax": Decimal, 
            "payment": Decimal 
        } 
    } 

Below is a sample request message.

Copy

    "status": "assign_member", 
    "timestamp": "2017-09-27T00:00:00Z", 
    "store_id": "1", 
    "terminal_id": "1", 
    "transaction_id": "1", 
    "operator_id": "1", 
    "accounts": [ 
        { 
            "identifier": "370615108474724", 
            "identifier_type": "card_id" 
        } 
    ], 
    "items": [ 
        { 
            "level": 0, 
            "line_number": 1, 
            "parent_line_number": 0, 
            "name": "Fries", 
            "description": "Cheese Fries", 
            "sku": "401301", 
            "categories": [ 
                "102" 
                ], 
            "quantity": 1, 
            "unit_price": 5.25, 
            "discountable": true 
        } 
    ],
    "coupons": [], 
    "summary": 
        { 
            "subtotal": 6.25, 
            "discount": 0.00, 
            "service_charge": 0.00, 
            "tax": 1.00, 
            "payment": 0.00 
        } 
    } 

Below is a sample response message to the above request.

Copy

    "messages": 
        { 
            "display": [ 
                { 
                    "message": "About to activate card #370615108474724.\\n Remind guest to register online to get\\n credit for their purchase." 
                } 
            ], 
        "receipt": [] 
    }, 
    "accounts": [ 
        { 
            "identifier": "370615108474724", 
            "valid": true 
        } 
    ] 

Replace Card

Clients can use this API to change the card ID for an existing Member account (for example, if the Member loses or damages their existing card). This API expects a Member identifier to retrieve the existing Member account and a new card ID to assign to the Member account.

Copy
PUT <base_url>?access_token=<access_token> 
{
    "status": "replace_card", 
    "timestamp": Timestamp, 
    "store_id": String, 
    "terminal_id": String, 
    "transaction_id": String,
    "operator_id": String, 
    "accounts": [ 
        { 
            "identifier": String, 
            "identifier_type": String 
        }, 
        { 
            "identifier": String, 
            "identifier_type": String 
        } 
    ] 
}

Below is a sample request message.

Copy

    "status": "replace_card", 
    "timestamp": "2017-09-27T00:00:00Z", 
    "store_id": "1", 
    "terminal_id": "1", 
    "transaction_id": "1", 
    "operator_id": "1", 
    "accounts": [ 
        { 
            "identifier": "michael@jordan.com", 
            "identifier_type": "email" 
        }, 
        { 
            "identifier": "6011888052563949", 
            "identifier_type": "card_id" 
        } 
    ] 

Below is a sample response message to the above request.

Copy

    "messages": 
        { 
            "display": [ 
                { 
                    "message": "Card #6011888052563949 is now associated\\n to 
guest - Michael Jordan." 
                } 
            ], 
            "receipt": [] 
        }, 
    "accounts": [ 
        { 
            "identifier": "michael@jordan.com", 
            "valid": true, 
            "name": "Michael Jordan", 
            "member_id": "S-000105990" 
        }, 
        { 
            "identifier": "6011888052563949", 
            "valid": true 
        } 
    ]